package fast;

/**
 * Buffer class
 * 
 * Provides a circular buffer of Strings
 * 
 * @version 0.1
 * @author Adam Bell
 * @date 17/12/2009
 */
public class Buffer {
	private String[] array;
	private boolean canAdd;
	private boolean canRemove;
	private int size;
	private int head;
	private int tail;
	private int n;

	/**
	 * Constructor
	 * 
	 * @param setSize
	 *            The size of the buffer to create. Should be at least the
	 *            number of slaves
	 */
	public Buffer(int setSize) {
		this.size = setSize;
		array = new String[setSize];
		head = 0;
		tail = 0;
		n = 0;
		canAdd = true;
		canRemove = false;
	}

	/**
	 * Add a string to the buffer
	 * 
	 * @param data
	 *            The data to be added
	 * @throws InterruptedException
	 */
	public synchronized void add(String data) throws InterruptedException {
		while (!canAdd)
			wait();

		array[head] = data;

		n = n + 1;
		head = (head + 1) % size;
		canRemove = true;
		canAdd = n < size;
		notifyAll();
	}// add()

	/**
	 * Add a series of tokens to the buffer, as a String
	 * 
	 * @param addr
	 *            Address of the remote host
	 * @param port
	 *            port on the remote host
	 * @param id
	 *            Message ID
	 * @param cmd
	 *            Command
	 * @param data
	 *            Data relating to the command
	 * @throws InterruptedException
	 */
	public synchronized void add(String addr, int port, int id, String cmd,
			String data) throws InterruptedException {

		while (!canAdd)
			wait();

		array[head] = addr + "|" + String.valueOf(port) + "|"
				+ String.valueOf(id) + "|" + cmd + "|" + data;

		n = n + 1;
		head = (head + 1) % size;
		canRemove = true;
		canAdd = n < size;
		notifyAll();
	}// add()

	/**
	 * Remove a string from the buffer
	 * 
	 * @return
	 * @throws InterruptedException
	 */
	public synchronized String remove() throws InterruptedException {
		while (!canRemove)
			this.wait();

		String returnStr = array[tail];
		array[tail] = "";

		n = n - 1;
		tail = (tail + 1) % size;
		canRemove = n > 0;
		canAdd = n < size;
		notifyAll();

		return returnStr;
	}// remove()

	/**
	 * Gets the number of entries currently in the buffer
	 * 
	 * @return int number of entries currently in the buffer
	 */
	public int getCount() {
		return n;
	}
}
